package com.smedi.ismedi.personnel.core.application.service.impl;

import com.smedi.ismedi.authority.starter.util.VerifyHelper;
import com.smedi.ismedi.constructionproject.api.dto.request.ProjectAssignmentRequest;
import com.smedi.ismedi.constructionproject.api.dto.response.ProjectAssignmentResponse;
import com.smedi.ismedi.constructionproject.api.feign.RemoteConstructionProjectFeignApi;
import com.smedi.ismedi.constructionproject.api.feign.RemoteProjectAssignmentFeignApi;
import com.smedi.ismedi.personnel.core.application.command.PersonAssigmentCommand;
import com.smedi.ismedi.personnel.core.application.command.PersonBasicCommand;
import com.smedi.ismedi.personnel.core.application.command.PersonEditCommand;
import com.smedi.ismedi.personnel.core.application.command.PersonOneQueryCommand;
import com.smedi.ismedi.personnel.core.application.query.PersonQueryService;
import com.smedi.ismedi.personnel.core.application.service.PersonApplicationService;
import com.smedi.ismedi.personnel.core.domain.aggregatemodel.*;
import com.smedi.ismedi.personnel.core.domain.aggregatemodel.model.SimplePerson;
import com.smedi.ismedi.personnel.core.domain.repository.PersonRepository;
import com.smedi.ismedi.personnel.core.domain.service.AssignmentDomainService;
import com.smedi.ismedi.personnel.core.domain.service.PersonDomainService;
import com.smedi.ismedi.personnel.core.domain.service.ProfileImageDomainService;
import com.smedi.ismedi.personnel.core.domain.service.SignatureDomainService;
import com.smedi.ismedi.personnel.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.personnel.core.infrastructure.enumerate.PersonStatusEnum;
import com.smedi.ismedi.personnel.core.infrastructure.enumerate.PersonTypeEnum;
import com.smedi.ismedi.personnel.core.port.adapter.convert.AdapterConverter;
import com.smedi.ismedi.personnel.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.personnel.core.port.adapter.service.UserManagementRemoteApiService;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.smedi.ismedi.personnel.core.infrastructure.constant.CustomError.ID_CARD_DUPLICATE;
import static com.smedi.ismedi.personnel.core.infrastructure.constant.CustomError.MOBILE_DUPLICATE;

/**
 * @Author: xulinjun
 * @Date: 2021-6-8 13:52
 */
@Slf4j
@Service
@AllArgsConstructor
public class PersonApplicationServiceImpl implements PersonApplicationService {
    private final PersonDomainService personDomainService;
    private final AssignmentDomainService assignmentDomainService;
    private final ProfileImageDomainService profileImageDomainService;
    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;
    private final UserManagementRemoteApiService userManagementRemoteApiService;
    private final SignatureDomainService signatureDomainService;
    private final RemoteConstructionProjectFeignApi remoteConstructionProjectFeignApi;
    private final RemoteProjectAssignmentFeignApi remoteProjectAssignmentFeignApi;
    private final PersonQueryService personQueryService;
    private final PersonRepository personRepository;
    private final DozerUtil dozerUtil;
    private final AdapterConverter adapterConverter;
    private final VerifyHelper verifyHelper;


    /**
     * 保存附属信息
     *
     * @param personBasicCommand
     * @param person
     * @param createAccount
     */
    private void saveAdditionalData(PersonBasicCommand personBasicCommand, Person person, boolean createAccount) {
        // 保存头像信息
        if (personBasicCommand.getImageUUID() != null) {
            ProfileImage profileImage = profileImageDomainService.saveProfileImage(personBasicCommand.getImageUUID(), person.getPersonId());
            person.setProfileImage(profileImage);
        }

        // 保存签章信息
        if (personBasicCommand.getSignatureUUID() != null) {
            Signature signature = signatureDomainService.saveSignature(personBasicCommand.getSignatureUUID(), person.getPersonId());
            person.setSignature(signature);
        }

        // 创建用户信息
        if (createAccount) {
            personDomainService.createAccount(person);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Person saveInternalPerson(PersonBasicCommand personBasicCommand) {
        // 保存人员信息
        Person person = dozerUtil.convertor(personBasicCommand, Person.class);
        //执行数据库的查询操作，确保手机号的唯一性
        List<Person> uncertaintyPerson = personRepository.selectByMobile(person.getMobile(),false);
        for (Person personTemp : uncertaintyPerson) {
            if (null == personBasicCommand.getPersonId()) {
                throw LogicException.raise(MOBILE_DUPLICATE);
            }
            if (!personBasicCommand.getPersonId().equals(personTemp.getPersonId())) {
                throw LogicException.raise(MOBILE_DUPLICATE);
            }
        }

        boolean createAccount = person.getPersonId() == null;
        boolean mobileChanged = personDomainService.isMobileChanged(person.getPersonId(), person.getMobile());

        person = personDomainService.saveInternalPerson(person);

        // 企业人员分配保存
        PersonAssigmentCommand personAssigmentCommand = personBasicCommand.getPersonAssigmentCommand();
        if (personAssigmentCommand != null) {
            if (personAssigmentCommand.getPersonId() == null) {
                personAssigmentCommand.setPersonId(person.getPersonId());
            }

            Assignment assignment = dozerUtil.convertor(personAssigmentCommand, Assignment.class);
            assignment = assignmentDomainService.saveAssignment(assignment);
            person.getInternalAssignments().add(assignment);
        } else {
            throw LogicException.raise(CustomError.ASSIGNMENT_MISS);
        }

        saveAdditionalData(personBasicCommand, person, createAccount);

        // 如果移动手机号发生变更，则需要调整
        if (mobileChanged) {
            userManagementRemoteApiService.changeAccountMobile(person.getPersonId(), person.getMobile());
        }


        return person;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Person saveExternalPerson(PersonBasicCommand personBasicCommand) {
        // 保存人员信息
        Person person = dozerUtil.convertor(personBasicCommand, Person.class);
        boolean createAccount = person.getPersonId() == null;
        boolean mobileChanged = personDomainService.isMobileChanged(person.getPersonId(), person.getMobile());

        person = personDomainService.saveExternalPerson(person);

        // 调用项目接口生成项目分配信息
        ProjectAssignmentRequest projectAssignmentRequest = new ProjectAssignmentRequest()
                .setPersonId(person.getPersonId())
                .setProjectId(personBasicCommand.getProjectAssigmentCommand().getProjectId())
                .setProjectJob(personBasicCommand.getProjectAssigmentCommand().getProjectJob())
                .setProjectOrganizationId(personBasicCommand.getProjectAssigmentCommand().getProjectOrganizationId())
                .setProjectAssignmentId(personBasicCommand.getProjectAssigmentCommand().getProjectAssignmentId());
        ProjectAssignmentResponse projectAssignmentResponse = new ProjectAssignmentResponse();
        if (null != projectAssignmentRequest.getPersonId() && null != projectAssignmentRequest.getProjectId() && null != projectAssignmentRequest.getProjectOrganizationId()) {
            projectAssignmentResponse = constructionProjectRemoteApiService.saveProjectAssignment(projectAssignmentRequest);
        }
        Assignment assignment = dozerUtil.convertor(projectAssignmentResponse, Assignment.class);
        person.getProjectAssignments().add(assignment);

        saveAdditionalData(personBasicCommand, person, createAccount);

        // 如果移动手机号发生变更，则需要调整
        if (mobileChanged) {
            userManagementRemoteApiService.changeAccountMobile(person.getPersonId(), person.getMobile());
        }

        return person;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Person savePersonInfoWithOutImage(PersonSyncFromImis personSyncFromImis, Long hrOrganizationId) {
        // 保存人员信息
        Person person = dozerUtil.convertor(personSyncFromImis, Person.class)
                .setStatus(PersonStatusEnum.ENABLE.getValue()) // 状态
                .setInternal(true) // 企业人员
                .setPersonType(PersonTypeEnum.COMPANY_MEMBER.getValue()); // 人员类型
        boolean createAccount = person.getPersonId() == null;
        boolean mobileChanged = personDomainService.isMobileChanged(person.getPersonId(), person.getMobile());

        person = personDomainService.saveInternalPerson(person);

        // 企业人员分配保存
        Assignment assignment = new Assignment()
                .setPersonId(person.getPersonId())
                .setHrJob(personSyncFromImis.getHrJob())
                .setHrOrganizationId(hrOrganizationId);
        assignment = assignmentDomainService.saveAssignment(assignment);
        person.getInternalAssignments().add(assignment);

        // 创建用户信息
        if (createAccount) {
            personDomainService.createAccount(person);
        }

        // 如果移动手机号发生变更，则需要调整
        if (mobileChanged) {
            userManagementRemoteApiService.changeAccountMobile(person.getPersonId(), person.getMobile());
        }

        return person;
    }

    @Override
    public Person saveProjectPersonInfoWithOutImage(PersonSyncFromImis personSyncFromImis, Long projectId, Long projectOrganizationId) {
        // 保存人员信息
        Person person = dozerUtil.convertor(personSyncFromImis, Person.class)
                .setStatus(PersonStatusEnum.ENABLE.getValue()) // 状态
                .setInternal(true) // 企业人员
                .setPersonType(PersonTypeEnum.COMPANY_MEMBER.getValue()); // 人员类型
        boolean createAccount = person.getPersonId() == null;
        boolean mobileChanged = personDomainService.isMobileChanged(person.getPersonId(), person.getMobile());

        person = personDomainService.saveInternalPerson(person);

        // 企业人员分配保存
        ProjectAssignmentRequest projectAssignmentRequest = new ProjectAssignmentRequest();
        projectAssignmentRequest.setPersonId(person.getPersonId())
                .setProjectId(projectId)
                .setProjectJob(personSyncFromImis.getHrJob())
                .setProjectOrganizationId(projectOrganizationId);

        ProjectAssignmentResponse projectAssignmentResponse = constructionProjectRemoteApiService.saveProjectAssignment(projectAssignmentRequest);
        person.getProjectAssignments().add(dozerUtil.convertor(projectAssignmentResponse, Assignment.class));

        // 创建用户信息
        if (createAccount) {
            personDomainService.createAccount(person);
        }

        // 如果移动手机号发生变更，则需要调整
        if (mobileChanged) {
            userManagementRemoteApiService.changeAccountMobile(person.getPersonId(), person.getMobile());
        }

        return person;
    }

    @Override
    public Boolean checkHrOrganizationHasPerson(Long orgId) {
        return assignmentDomainService.checkHrOrganizationHasAssignments(orgId);
    }

    @Override
    public Boolean checkPersonIsInternal(Long personId) {
        return personDomainService.isInternal(personId);
    }

    @Override
    public Boolean checkPersonIsExternal(Long personId) {
        return personDomainService.isExternal(personId);
    }

    @Override
    public Boolean checkPersonAvailable(Long personId) {
        return personDomainService.isAvailable(personId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editPersonStatus(Long personId, boolean enable) {
        personDomainService.editPersonStatus(personId, enable);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePersonBasicAndAllAssignments(Long personId) {
        // 删除项目分配
        constructionProjectRemoteApiService.deleteProjectAssignmentsByPersonId(personId);

        // 删除企业分配
        assignmentDomainService.deleteInternalAssignmentsByPersonId(personId);

        // 删除人员信息
        personDomainService.deleteByPersonId(personId);

        // 删除人员账号
        userManagementRemoteApiService.deleteAccountOnly(personId);
    }

    @Override
    @Transactional
    public boolean postBatchAddExistingPerson(List<Long> personIds, long organizationId) {
        List<ProjectAssignmentResponse> projectAssignmentResponses = remoteProjectAssignmentFeignApi.getQueryProjectAssignmentsByPersonIds(personIds).getData();
        Map<Long, List<ProjectAssignmentResponse>> longProjectAssignmentsMap = projectAssignmentResponses.stream().collect(Collectors.groupingBy(ProjectAssignmentResponse::getPersonId));
        for (Long personId : personIds) {
            Assignment assignment = new Assignment();
            assignment.setPersonId(personId);
            assignment.setHrOrganizationId(organizationId);
            List<ProjectAssignmentResponse> projectAssignmentResponsesByPerson = longProjectAssignmentsMap.getOrDefault(personId, new ArrayList<>());
            if (!projectAssignmentResponsesByPerson.isEmpty()) {
                String projectJob = projectAssignmentResponsesByPerson.get(0).getProjectJob();
                assignment.setHrJob(null != projectJob ? projectJob : "待定");
            } else {
                assignment.setHrJob("待定");
            }
            assignment.setPersonId(personId);
            assignmentDomainService.saveAssignment(assignment);
        }
        return true;
    }

    @Override
    public void editPerson(PersonEditCommand personEditCommand) {
        SimplePerson person = adapterConverter.personEditCommandToSimplePerson(personEditCommand);

        if (verifyHelper.isAvailable(personEditCommand.getMobile()) || verifyHelper.isAvailable(personEditCommand.getIdCard())) {
            SimplePerson personLast = personQueryService.getSimplePersonOne(PersonOneQueryCommand.builder().id(personEditCommand.getId()).build());

            if (verifyHelper.isAvailable(personEditCommand.getMobile()) && !person.getMobile().equals(personLast.getMobile())) {
                if (null != personQueryService.getSimplePersonOne(PersonOneQueryCommand.builder().mobile(person.getMobile()).build())) {
                    throw LogicException.raise(MOBILE_DUPLICATE);
                }
            }

            if (verifyHelper.isAvailable(personEditCommand.getIdCard()) && !person.getIdCard().equals(personLast.getIdCard())) {
                if (null != personQueryService.getSimplePersonOne(PersonOneQueryCommand.builder().idCard(person.getIdCard()).build())) {
                    throw LogicException.raise(ID_CARD_DUPLICATE);
                }
            }
        }

        personDomainService.editSimplePerson(person);
    }
}
